#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<fstream>
#include<vector>
#include<cctype>
#include<algorithm>
#include<sstream>
#include<random>
#include<unordered_set>
using namespace std;
enum parts  //标识每种器件对应的编号
{
    Illegal=0, VoltS, CurrS, Reg, Capc, Lth, nLoop, nShort, bOpen
};
class package  //标识识别出的器件种类和给定数量
{
public:
    int kind,num;
    package(int a,int b):kind(a),num(b){}
};
bool check_legal(int V, int I, int R, int C, int L, int nLoop, int nShort, bool bOpen) //约束条件，判定是否可以生成符合要求的网表
{
    if (V < nShort) return false;  //电压源数量必须不少于短路数量
    if (V + I < nLoop + (bOpen ? 1 : 0)) return false;  //电源数量必须不少于总回路数量，并且假设开路至少一个，也需要给开路分配电源 
    if (R + L + C < max(nLoop - nShort - I, 0) + max(nShort - nLoop, 0)) return false; //无源器件要满足:在有多余电压源组成空余回路时，防止形成短路和当短路多于回路时，将不同短路和回路间连接起来

    return true;
}
string trimLeft(const string& str) {  //将每行前面的空白符删去
    size_t start = 0;
    // ?????????????????????
    while (start < str.length() && isspace(str[start])) {
        ++start;
    }
    return str.substr(start);
}
vector<string> split(const string& str, char delimiter = ' ') {  //分割每行的内容，得到子串
    vector<string> result;
    string temp;
    istringstream stream(str);

    while (stream >> temp) {
        result.push_back(temp);
    }

    return result;
}
package check_legal(vector<string> subs) //识别改行给定的器件类型，读取给定数量。含有非数字字符和负号无视掉。若该行没有识别到数量，则记为0。若该行为识别出正确器件，则无视该行输入。
{
    bool check=false;
    int cate=0;
    int num=0;
    for(int i=0; i<subs.size(); i++)
    {
        int pos = subs[i].find("nVoltS");
        if(pos!=subs[i].npos)
        {
            cate=1;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("nCurrS");
        if(pos!=subs[i].npos)
        {
            cate=2;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("nR");
        if(pos!=subs[i].npos)
        {
            cate=3;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("nC");
        if(pos!=subs[i].npos)
        {
            cate=4;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("nLoop");
        if(pos!=subs[i].npos)
        {
            cate=6;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("nL");
        if(pos!=subs[i].npos)
        {
            cate=5;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("nShort");
        if(pos!=subs[i].npos)
        {
            cate=7;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            return package(cate,num);
        }
        pos = subs[i].find("bOpen");
        if(pos!=subs[i].npos)
        {
            cate=8;
            for(int j=i+1;j<subs.size();j++)
            {
                if(!subs[j].empty() && all_of(subs[j].begin(), subs[j].end(), ::isdigit))
                {
                    num = stoi(subs[j]);
                }
            }
            if(num>0) num=1;
            else num=0;
            return package(cate,num);
        }
    }
    return package(Illegal,0);
}
class BasicComponent  //分配的器件最基础的属性，类型和编号
{
public:
    char type;
    int id;

    BasicComponent(char t,int i):type(t),id(i){}
};
class BasicCircuit
{
public:
    vector<vector<BasicComponent*>> loops;  //各个loop分配到的器件列表
    vector<BasicComponent*> shorts; //临时存放短路分配的器件
    vector<BasicComponent*> open; 
};

class CircuitAllocator {  //分配所有元件
    vector<BasicComponent*> all_V;
    vector<BasicComponent*> all_I;
    vector<BasicComponent*> passives;
    
    random_device rd; //生成随机数
    mt19937 gen;
    
    
    template<typename T>
    BasicComponent* extract_random(T& container) {  //随机取出容器内的一个器件
        uniform_int_distribution<> dis(0, container.size()-1);
        int idx = dis(gen);
        BasicComponent* c = container[idx];
        container.erase(container.begin() + idx);
        return c;
    }

public:
    CircuitAllocator(int R, int L, int C, int V, int I) : gen(rd()) {
        // 产生器件对象
        for(int i=0; i<V; i++) all_V.push_back(new BasicComponent('V', i+1));
        for(int i=0; i<I; i++) all_I.push_back(new BasicComponent('I', i+1));
        for(int i=0; i<R; i++) passives.push_back(new BasicComponent('R', i+1));
        for(int i=0; i<L; i++) passives.push_back(new BasicComponent('L', i+1));
        for(int i=0; i<C; i++) passives.push_back(new BasicComponent('C', i+1));
        
        //打乱容器内器件编号
        
        shuffle(all_V.begin(), all_V.end(), gen);
        shuffle(all_I.begin(), all_I.end(), gen);
        shuffle(passives.begin(), passives.end(), gen);
    }

    BasicCircuit* allocate(int total_loops, int short_count, bool bOpen) {
        BasicCircuit* circuit = new BasicCircuit;
        
        //预先为短路回路分配电源
        for(int i=0; i<short_count && !all_V.empty(); i++) {
            circuit->shorts.push_back(extract_random(all_V));
            //cout<<circuit->shorts.back()->type<<' '<<circuit->shorts.back()->id<<endl;
        }
		
        //给其余回路分配器件和电源
        int remaining_loops = total_loops;
        while(remaining_loops > 0) {
            vector<BasicComponent*> new_loop;
            
            
            /*
            if(!circuit->shorts.empty() && (gen()%100 < 30)) {
                new_loop.push_back(circuit->shorts[gen()%circuit->shorts.size()]);
            }
			*/
            
            if(!all_I.empty() && (gen()%2 || all_V.empty())) {
                new_loop.push_back(extract_random(all_I));
            } else if(!all_V.empty()) {
                new_loop.push_back(extract_random(all_V));
                
                if(!passives.empty()) {
                    new_loop.push_back(extract_random(passives));
                }
            }

            // 平均每个回路可以分配到 总无源器件数/余下回路，电源 个元件
            int allo ;
            if(all_I.size()+all_V.size()==0) allo = passives.size();
            else if(passives.size()/(all_I.size()+all_V.size())==0) allo = gen()%2;
            else allo = gen()%(passives.size()/(all_I.size()+all_V.size()));
            //cout<<allo<<endl;
            for(int i=0; i<allo && !passives.empty(); i++) {
                new_loop.push_back(extract_random(passives));
            }
			//cout<<"breakpoint1"<<endl;
            if(!new_loop.empty()) {
                circuit->loops.push_back(new_loop);
                --remaining_loops;
            }
			//cout<<"breakpoint2"<<endl;
        }

        // 给开路分配器件
        if(bOpen) {
            
            if(!all_V.empty()) {
                circuit->open.push_back(extract_random(all_V));
            } else if(!all_I.empty()) {
                circuit->open.push_back(extract_random(all_I));
            }
        }  //未用上的器件全部放入倒数第一个回路内
        while(!all_V.empty())
        {
            circuit->loops[nLoop-1].push_back(extract_random(all_V));
        }
        while(!all_I.empty())
        {
            circuit->loops[nLoop-1].push_back(extract_random(all_I));
        }
        while(!passives.empty())
        {
            circuit->loops[nLoop-1].push_back(extract_random(passives));
        }
        return circuit;
    }

    
};
bool readParameter(int& nV,int& nI,int& nR,int& nC,int& nL,int& nShort,int& nLoop,bool& bOpen) //读入数据
{
	ifstream infile;
	ofstream outfile;
    infile.open("netlistConfig");
    outfile.open("netlistDump.sp");
    nI = 0; nV = 0; nC = 0; nR = 0; nL = 0; nShort = 0; nLoop = 0;
    bOpen = false;
    string buf;
    buf.clear();
    if(!infile.is_open()) //未打开输入文件输出文件都报错
    {
        streambuf* old_cerr = cerr.rdbuf();
        cerr.rdbuf(outfile.rdbuf()); 
        cerr<<"Unable to open file netlistConfig."<<endl;
        cerr.rdbuf(old_cerr);
        
    infile.close();
    outfile.close();
        return true;
    }
    if (!outfile.is_open()) {
        streambuf* old_cerr = cerr.rdbuf();
        cerr.rdbuf(outfile.rdbuf()); 
        cerr << "Unable to open file netlistDump.sp." << endl;
        cerr.rdbuf(old_cerr);
        
    infile.close();
    outfile.close();
        return true;
    }
    vector<string> subs;
    buf.clear();
    while(getline(infile, buf))  //识别每一行读入内容，并加到对应器件数目
    {
        buf = trimLeft(buf);
        if(!buf.empty())
        {
            subs.clear();
            subs = split(buf);
            package recognise_part = check_legal(subs);
            if(recognise_part.kind>0)
            {
                if(recognise_part.kind==1) nV+=recognise_part.num;
                if(recognise_part.kind==2) nI+=recognise_part.num;
                if(recognise_part.kind==3) nR+=recognise_part.num;
                if(recognise_part.kind==4) nC+=recognise_part.num;
                if(recognise_part.kind==5) nL+=recognise_part.num;
                if(recognise_part.kind==7) nShort+=recognise_part.num;
                if(recognise_part.kind==6) nLoop+=recognise_part.num;
                if(recognise_part.kind==8) bOpen=bOpen|recognise_part.num;

            }
        }
        buf.clear();
    }
    if(nV==0&&nI==0&&nR==0&&nC==0&&nL==0&&nLoop==0&&nShort==0&&bOpen==false)  //没有给定器件则报错
    {
        streambuf* old_cerr = cerr.rdbuf();
        cerr.rdbuf(outfile.rdbuf()); 
        cerr<<"No parameters given."<<endl;
        cerr.rdbuf(old_cerr);
    	infile.close();
    	outfile.close();
        return 1;
    }
	
	//检验无法生成最小限度的网表也报错
    if(!check_legal(nV,nI,nR,nC,nL,nLoop,nShort,bOpen))
    {
        streambuf* old_cerr = cerr.rdbuf();
        cerr.rdbuf(outfile.rdbuf()); 
        cerr<<"Cannot generate compliant netlist."<<endl;
        cerr.rdbuf(old_cerr);
    	infile.close();
    	outfile.close();
        return 1;
    }
    return false;
}






